package com.lineage.server.utils;

import com.lineage.config.ConfigGuaji;
import com.lineage.config.ConfigOther;
import com.lineage.config.ConfigRate;
import com.lineage.data.event.LeavesSet;
import com.lineage.server.datatables.ExpTable;
import com.lineage.server.datatables.Explogpcpower;
import com.lineage.server.datatables.MapsTable;
import com.lineage.server.datatables.lock.PetReading;
import com.lineage.server.model.Instance.L1ItemInstance;
import com.lineage.server.model.Instance.L1NpcInstance;
import com.lineage.server.model.Instance.L1PcInstance;
import com.lineage.server.model.Instance.L1PetInstance;
import com.lineage.server.model.Instance.L1SummonInstance;
import com.lineage.server.model.L1Character;
import com.lineage.server.model.L1Object;
import com.lineage.server.model.L1Party;
import com.lineage.server.serverpackets.S_ItemName;
import com.lineage.server.serverpackets.S_NPCPack_Pet;
import com.lineage.server.serverpackets.S_PacketBoxExp;
import com.lineage.server.serverpackets.S_ServerMessage;
import com.lineage.server.serverpackets.ServerBasePacket;
import com.lineage.server.templates.L1Pet;
import com.lineage.server.world.World;
import com.lineage.server.world.WorldItem;
import java.util.ArrayList;
import java.util.Iterator;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class CalcExp {
  private static final Log _log = LogFactory.getLog(CalcExp.class);
  
  public static void calcExp(L1PcInstance srcpc, int targetid, ArrayList<?> acquisitorList, ArrayList<Integer> hateList, long exp) {
    try {
      int i = 0;
      double party_level = 0.0D;
      double dist = 0.0D;
      long member_exp = 0L;
      int member_lawful = 0;
      L1Object object = World.get().findObject(targetid);
      L1NpcInstance npc = null;
      if (!(object instanceof L1NpcInstance))
        return; 
      npc = (L1NpcInstance)object;
      int hate = 0;
      long acquire_exp = 0L;
      int acquire_lawful = 0;
      long party_exp = 0L;
      int party_lawful = 0;
      long totalHateExp = 0L;
      int totalHateLawful = 0;
      long partyHateExp = 0L;
      int partyHateLawful = 0;
      long ownHateExp = 0L;
      if (acquisitorList.size() != hateList.size())
        return; 
      i = hateList.size() - 1;
      while (i >= 0) {
        L1Character acquisitor = (L1Character)acquisitorList.get(i);
        hate = ((Integer)hateList.get(i)).intValue();
        boolean isRemove = false;
        if (acquisitor instanceof com.lineage.server.model.Instance.L1IllusoryInstance)
          isRemove = true; 
        if (acquisitor instanceof com.lineage.server.model.Instance.L1EffectInstance)
          isRemove = true; 
        if (isRemove) {
          if (acquisitor != null) {
            acquisitorList.remove(i);
            hateList.remove(i);
          } 
        } else if (acquisitor != null && !acquisitor.isDead()) {
          totalHateExp += hate;
          if (acquisitor instanceof L1PcInstance)
            totalHateLawful += hate; 
        } else {
          acquisitorList.remove(i);
          hateList.remove(i);
        } 
        i--;
      } 
      if (totalHateExp == 0L)
        return; 
      if (object != null && !(npc instanceof L1PetInstance) && !(npc instanceof L1SummonInstance)) {
        if (!World.get().isProcessingContributionTotal() && srcpc.getHomeTownId() > 0) {
          int contribution = npc.getLevel() / 10;
          srcpc.addContribution(contribution);
        } 
        int lawful = npc.getLawful();
        if (srcpc.isInParty()) {
          partyHateExp = 0L;
          partyHateLawful = 0;
          i = hateList.size() - 1;
          while (i >= 0) {
            L1Character acquisitor2 = (L1Character)acquisitorList.get(i);
            hate = ((Integer)hateList.get(i)).intValue();
            if (acquisitor2 instanceof L1PcInstance) {
              L1PcInstance pc = (L1PcInstance)acquisitor2;
              if (pc == srcpc) {
                partyHateExp += hate;
                partyHateLawful += hate;
              } else if (srcpc.getParty().isMember(pc)) {
                partyHateExp += hate;
                partyHateLawful += hate;
              } else {
                if (totalHateExp > 0L)
                  acquire_exp = exp * hate / totalHateExp; 
                if (totalHateLawful > 0)
                  acquire_lawful = lawful * hate / totalHateLawful; 
                addExp(pc, acquire_exp, acquire_lawful);
              } 
            } else if (acquisitor2 instanceof L1PetInstance) {
              L1PetInstance pet = (L1PetInstance)acquisitor2;
              L1PcInstance master = (L1PcInstance)pet.getMaster();
              if (master == srcpc) {
                partyHateExp += hate;
              } else if (srcpc.getParty().isMember(master)) {
                partyHateExp += hate;
              } else {
                if (totalHateExp > 0L)
                  acquire_exp = exp * hate / totalHateExp; 
                addExpPet(pet, acquire_exp);
              } 
            } else if (acquisitor2 instanceof L1SummonInstance) {
              L1SummonInstance summon = (L1SummonInstance)acquisitor2;
              L1PcInstance master = (L1PcInstance)summon.getMaster();
              if (master == srcpc) {
                partyHateExp += hate;
              } else if (srcpc.getParty().isMember(master)) {
                partyHateExp += hate;
              } 
            } 
            i--;
          } 
          if (totalHateExp > 0L)
            party_exp = exp * partyHateExp / totalHateExp; 
          if (totalHateLawful > 0)
            party_lawful = lawful * partyHateLawful / totalHateLawful; 
          double pri_bonus = 0.0D;
          L1PcInstance leader = srcpc.getParty().getLeader();
          if (leader.isCrown() && (srcpc.knownsObject((L1Object)leader) || srcpc.equals(leader)))
            pri_bonus = 0.059D; 
          Object[] pcs = srcpc.getParty().partyUsers().values().toArray();
          double pt_bonus = 0.0D;
          Object[] array;
          int n = (array = pcs).length;
          int j = 0;
          while (j < n) {
            Object obj = array[j];
            if (obj instanceof L1PcInstance) {
              L1PcInstance each = (L1PcInstance)obj;
              if (!each.isDead()) {
                if (srcpc.knownsObject((L1Object)each) || srcpc.equals(each))
                  party_level += (each.getLevel() * each.getLevel()); 
                if (srcpc.knownsObject((L1Object)each))
                  pt_bonus += 0.04D; 
              } 
            } 
            j++;
          } 
          party_exp = (long)(party_exp * (1.0D + pt_bonus + pri_bonus));
          if (party_level > 0.0D)
            dist = (srcpc.getLevel() * srcpc.getLevel()) / party_level; 
          member_exp = (long)(party_exp * dist);
          member_lawful = (int)(party_lawful * dist);
          ownHateExp = 0L;
          i = hateList.size() - 1;
          while (i >= 0) {
            L1Character acquisitor3 = (L1Character)acquisitorList.get(i);
            hate = ((Integer)hateList.get(i)).intValue();
            if (acquisitor3 instanceof L1PcInstance) {
              L1PcInstance pc2 = (L1PcInstance)acquisitor3;
              if (pc2 == srcpc)
                ownHateExp += hate; 
            } else if (acquisitor3 instanceof L1PetInstance) {
              L1PetInstance pet2 = (L1PetInstance)acquisitor3;
              L1PcInstance master2 = (L1PcInstance)pet2.getMaster();
              if (master2 == srcpc)
                ownHateExp += hate; 
            } else if (acquisitor3 instanceof L1SummonInstance) {
              L1SummonInstance summon2 = (L1SummonInstance)acquisitor3;
              L1PcInstance master2 = (L1PcInstance)summon2.getMaster();
              if (master2 == srcpc)
                ownHateExp += hate; 
            } 
            i--;
          } 
          if (ownHateExp != 0L) {
            i = hateList.size() - 1;
            while (i >= 0) {
              L1Character acquisitor3 = (L1Character)acquisitorList.get(i);
              hate = ((Integer)hateList.get(i)).intValue();
              if (acquisitor3 instanceof L1PcInstance) {
                L1PcInstance pc2 = (L1PcInstance)acquisitor3;
                if (pc2 == srcpc) {
                  if (ownHateExp > 0L)
                    acquire_exp = member_exp * hate / ownHateExp; 
                  addExp(pc2, acquire_exp, member_lawful);
                } 
              } else if (acquisitor3 instanceof L1PetInstance) {
                L1PetInstance pet2 = (L1PetInstance)acquisitor3;
                L1PcInstance master2 = (L1PcInstance)pet2.getMaster();
                if (master2 == srcpc) {
                  if (ownHateExp > 0L)
                    acquire_exp = member_exp * hate / ownHateExp; 
                  addExpPet(pet2, acquire_exp);
                } 
              } else {
                if(acquisitor3 instanceof L1SummonInstance)
                ;
              } 
              i--;
            } 
          } else {
            addExp(srcpc, member_exp, member_lawful);
          } 
          n = (array = pcs).length;
          j = 0;
          while (j < n) {
            Object obj = array[j];
            if (obj instanceof L1PcInstance) {
              L1PcInstance tgpc = (L1PcInstance)obj;
              if (!tgpc.isDead() && srcpc.knownsObject((L1Object)tgpc)) {
                if (party_level > 0.0D)
                  dist = (tgpc.getLevel() * tgpc.getLevel()) / party_level; 
                member_exp = (int)(party_exp * dist);
                member_lawful = (int)(party_lawful * dist);
                ownHateExp = 0L;
                i = hateList.size() - 1;
                while (i >= 0) {
                  L1Character acquisitor4 = (L1Character)acquisitorList.get(i);
                  hate = ((Integer)hateList.get(i)).intValue();
                  if (acquisitor4 instanceof L1PcInstance) {
                    L1PcInstance pc3 = (L1PcInstance)acquisitor4;
                    if (pc3 == tgpc)
                      ownHateExp += hate; 
                  } else if (acquisitor4 instanceof L1PetInstance) {
                    L1PetInstance pet3 = (L1PetInstance)acquisitor4;
                    L1PcInstance master3 = (L1PcInstance)pet3.getMaster();
                    if (master3 == tgpc)
                      ownHateExp += hate; 
                  } else if (acquisitor4 instanceof L1SummonInstance) {
                    L1SummonInstance summon3 = (L1SummonInstance)acquisitor4;
                    L1PcInstance master3 = (L1PcInstance)summon3.getMaster();
                    if (master3 == tgpc)
                      ownHateExp += hate; 
                  } 
                  i--;
                } 
                if (ownHateExp != 0L) {
                  i = hateList.size() - 1;
                  while (i >= 0) {
                    L1Character acquisitor4 = (L1Character)acquisitorList.get(i);
                    hate = ((Integer)hateList.get(i)).intValue();
                    if (acquisitor4 instanceof L1PcInstance) {
                      L1PcInstance pc3 = (L1PcInstance)acquisitor4;
                      if (pc3 == tgpc) {
                        if (ownHateExp > 0L)
                          acquire_exp = member_exp * hate / ownHateExp; 
                        addExp(pc3, acquire_exp, member_lawful);
                      } 
                    } else if (acquisitor4 instanceof L1PetInstance) {
                      L1PetInstance pet3 = (L1PetInstance)acquisitor4;
                      L1PcInstance master3 = (L1PcInstance)pet3.getMaster();
                      if (master3 == tgpc) {
                        if (ownHateExp > 0L)
                          acquire_exp = member_exp * hate / ownHateExp; 
                        addExpPet(pet3, acquire_exp);
                      } 
                    } else {
                      if(acquisitor4 instanceof L1SummonInstance)
                    	  ;
                    } 
                    i--;
                  } 
                } else {
                  addExp(tgpc, member_exp, member_lawful);
                } 
              } 
            } 
            j++;
          } 
        } else {
          i = hateList.size() - 1;
          while (i >= 0) {
            L1Character acquisitor2 = (L1Character)acquisitorList.get(i);
            hate = ((Integer)hateList.get(i)).intValue();
            acquire_exp = exp * hate / totalHateExp;
            if (acquisitor2 instanceof L1PcInstance && totalHateLawful > 0)
              acquire_lawful = lawful * hate / totalHateLawful; 
            if (acquisitor2 instanceof L1PcInstance) {
              L1PcInstance pc = (L1PcInstance)acquisitor2;
              addExp(pc, acquire_exp, acquire_lawful);
            } else if (acquisitor2 instanceof L1PetInstance) {
              L1PetInstance pet = (L1PetInstance)acquisitor2;
              addExpPet(pet, acquire_exp);
            } else {
              if(acquisitor2 instanceof L1SummonInstance);
            } 
            i--;
          } 
        } 
      } 
    } catch (Exception e) {
      _log.error(e.getLocalizedMessage(), e);
    } 
  }
  
  private static void addExp(L1PcInstance pc, long exp, int lawful) {
    try {
      double addExp = exp;
      int add_lawful = (int)(lawful * ConfigRate.RATE_LA) * -1;
      pc.addLawful(add_lawful);
      if (pc.getLevel() >= ExpTable.MAX_LEVEL)
        return; 
      if (LeavesSet.START && pc.getlogintime() > 0) {
        int add = (int)(addExp * 0.77D);
        int add2 = (int)addExp + add;
        int add3 = pc.getlogintime() - add2;
        if (add3 > 0) {
          pc.setlogintime(add3);
          pc.sendPackets((ServerBasePacket)new S_PacketBoxExp(pc.getlogintime() / LeavesSet.EXP));
        } else {
          add = pc.getlogintime();
          pc.setlogintime(0);
          pc.sendPackets((ServerBasePacket)new S_PacketBoxExp());
        } 
        addExp += add;
      } 
      double exppenalty = ExpTable.getPenaltyRate(pc.getLevel(), pc.getMeteLevel());
      if (exppenalty < 1.0D)
        addExp *= exppenalty; 
      if (ConfigRate.RATE_XP > 1.0D)
        addExp *= ConfigRate.RATE_XP; 
      if (MapsTable.get().getEXP(pc.getMapId()) > 100.0D)
        addExp *= MapsTable.get().getEXP(pc.getMapId()) / 100.0D; 
      addExp *= add(pc);
      addExp *= Explogpcpower.get().getRate(pc.getMeteLevel());
      if (addExp < 0.0D) {
        addExp = 0.0D;
      } else if (addExp > 3.6065092E7D) {
        addExp = 3.6065092E7D;
      } 
      pc.addExp((long)addExp);
    } catch (Exception e) {
      _log.error(e.getLocalizedMessage(), e);
    } 
  }
  
  private static double add(L1PcInstance pc) {
    try {
      double add_exp = 0.0D;
      if (pc.hasSkillEffect(8591))
        add_exp++; 
      if (pc.getExpPoint() > 0)
        add_exp += pc.getExpPoint() / 100.0D; 
      if (pc.hasSkillEffect(3007) || pc.hasSkillEffect(3015))
        add_exp += 0.01D; 
      if (pc.hasSkillEffect(3023) || pc.hasSkillEffect(3031))
        add_exp += 0.02D; 
      if (pc.hasSkillEffect(3039) || pc.hasSkillEffect(3047))
        add_exp += 0.03D; 
      if (pc.hasSkillEffect(3048) || pc.hasSkillEffect(3049) || pc.hasSkillEffect(3050))
        add_exp += 0.02D; 
      if (pc.hasSkillEffect(3051))
        add_exp += 0.04D; 
      if (pc.hasSkillEffect(6666))
        add_exp += 1.3D; 
      if (pc.hasSkillEffect(6667))
        add_exp += 1.5D; 
      if (pc.hasSkillEffect(6668))
        add_exp += 1.7D; 
      if (pc.hasSkillEffect(6669))
        add_exp += 2.0D; 
      if (pc.hasSkillEffect(6670))
        add_exp += 2.5D; 
      if (pc.hasSkillEffect(6671))
        add_exp += 3.0D; 
      if (pc.hasSkillEffect(6672))
        add_exp += 3.5D; 
      if (pc.hasSkillEffect(6673))
        add_exp += 4.0D; 
      if (pc.hasSkillEffect(6674))
        add_exp += 4.5D; 
      if (pc.hasSkillEffect(6675))
        add_exp += 5.0D; 
      if (pc.hasSkillEffect(6676))
        add_exp += 5.5D; 
      if (pc.hasSkillEffect(6677))
        add_exp += 6.0D; 
      if (pc.hasSkillEffect(6678))
        add_exp += 6.5D; 
      if (pc.hasSkillEffect(6679))
        add_exp += 7.0D; 
      if (pc.hasSkillEffect(6680))
        add_exp += 7.5D; 
      if (pc.hasSkillEffect(6681))
        add_exp += 8.0D; 
      if (pc.getExpAdd() > 0.0D) {
        if (pc.getExpAdd() >= 1.0D)
          add_exp++; 
        add_exp += pc.getExpAdd();
      } 
      L1Party party = pc.getParty();
      if (ConfigOther.partyexp && party != null) {
        Iterator<L1PcInstance> iterator = World.get().getVisiblePlayer((L1Object)pc, 8).iterator();
        while (iterator.hasNext()) {
          L1PcInstance player = iterator.next();
          if (pc.getParty().isMember(player)) {
            int count = player.getParty().getNumOfMembers();
            if (count > 1)
              player.setPartyExp(ConfigOther.partyexp1 * count); 
          } 
          add_exp += pc.getPartyExp();
        } 
      } 
      if (pc.getExpByArmor() > 0.0D)
        add_exp += pc.getExpByArmor() / 100.0D; 
      double foodBonus = 0.0D;
      if (pc.hasSkillEffect(5000))
        foodBonus += 1.5D; 
      if (pc.hasSkillEffect(5001))
        foodBonus += 1.75D; 
      if (pc.hasSkillEffect(5002))
        foodBonus += 2.0D; 
      if (pc.hasSkillEffect(5003))
        foodBonus += 2.25D; 
      if (pc.hasSkillEffect(5004))
        foodBonus += 2.5D; 
      if (pc.hasSkillEffect(5005))
        foodBonus += 2.75D; 
      if (pc.hasSkillEffect(5006))
        foodBonus += 3.0D; 
      if (pc.hasSkillEffect(5007))
        foodBonus += 3.25D; 
      if (pc.hasSkillEffect(5008))
        foodBonus += 3.5D; 
      if (pc.hasSkillEffect(5009))
        foodBonus += 3.75D; 
      if (pc.hasSkillEffect(5010))
        foodBonus += 4.0D; 
      if (pc.hasSkillEffect(5011))
        foodBonus += 4.5D; 
      if (pc.hasSkillEffect(5012))
        foodBonus += 5.0D; 
      if (pc.hasSkillEffect(5013))
        foodBonus += 5.5D; 
      if (pc.hasSkillEffect(5014))
        foodBonus += 6.0D; 
      if (foodBonus > 0.0D)
        add_exp *= foodBonus; 
      if (add_exp < 1.0D)
        add_exp++; 
      if (pc.getguaji_count() > 0) {
        if (pc.isActived() || pc.get_followmaster() != null)
          add_exp *= ConfigGuaji.guaji_hu_exp; 
      } else if (pc.isActived() || pc.get_followmaster() != null) {
        add_exp *= ConfigGuaji.guajiexp2;
      } 
      return add_exp;
    } catch (Exception e) {
      _log.error(e.getLocalizedMessage(), e);
      return 1.0D;
    } 
  }
  
  private static void addExpPet(L1PetInstance pet, long exp) {
    try {
      if (pet == null)
        return; 
      if (pet.getPetType() == null)
        return; 
      L1PcInstance pc = (L1PcInstance)pet.getMaster();
      if (pc == null)
        return; 
      int petItemObjId = pet.getItemObjId();
      int levelBefore = pet.getLevel();
      long totalExp = exp * ConfigOther.petexp + pet.getExp();
      int maxLevel = ConfigOther.petlevel;
      if (totalExp >= ExpTable.getExpByLevel(maxLevel))
        totalExp = ExpTable.getExpByLevel(maxLevel) - 1L; 
      pet.setExp(totalExp);
      pet.setLevel(ExpTable.getLevelByExp(totalExp));
      int expPercentage = ExpTable.getExpPercentage(pet.getLevel(), totalExp);
      int gap = pet.getLevel() - levelBefore;
      int i = 1;
      while (i <= gap) {
        RangeInt hpUpRange = pet.getPetType().getHpUpRange();
        RangeInt mpUpRange = pet.getPetType().getMpUpRange();
        pet.addMaxHp(hpUpRange.randomValue());
        pet.addMaxMp(mpUpRange.randomValue());
        i++;
      } 
      pet.setExpPercent(expPercentage);
      pc.sendPackets((ServerBasePacket)new S_NPCPack_Pet(pet, pc));
      if (gap != 0) {
        L1Pet petTemplate = PetReading.get().getTemplate(petItemObjId);
        if (petTemplate == null)
          return; 
        petTemplate.set_exp((int)pet.getExp());
        petTemplate.set_level(pet.getLevel());
        petTemplate.set_hp(pet.getMaxHp());
        petTemplate.set_mp(pet.getMaxMp());
        PetReading.get().storePet(petTemplate);
        pc.sendPackets((ServerBasePacket)new S_ServerMessage(320, pet.getName()));
        L1ItemInstance item = WorldItem.get().getItem(Integer.valueOf(pet.getItemObjId()));
        pc.sendPackets((ServerBasePacket)new S_ItemName(item));
      } 
    } catch (Exception e) {
      _log.error(e.getLocalizedMessage(), e);
    } 
  }
}
